home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Snippets / PNL Libraries / Libraries / GIF / gifsave.c next >
Text File  |  1995-07-20  |  30KB  |  1,205 lines

  1.  
  2. /**************************************************************************
  3.  *
  4.  *  FILE:           GIFSAVE.C
  5.  *
  6.  *  MODULE OF:      GIFSAVE
  7.  *
  8.  *  DESCRIPTION:    Routines to create a GIF-file. See GIFSAVE.DOC for
  9.  *                  a description . . .
  10.  *
  11.  *                  The functions were originally written using Borland's
  12.  *                  C-compiler on an IBM PC -compatible computer, but they
  13.  *                  are compiled and tested on SunOS (Unix) as well.
  14.  *
  15.  *  WRITTEN BY:     Sverre H. Huseby
  16.  *                  Bjoelsengt. 17
  17.  *                  N-0468 Oslo
  18.  *                  Norway
  19.  *
  20.  *                  sverrehu@ifi.uio.no
  21.  *
  22.  *  LAST MODIFIED:  26/9-1992, v1.0, Sverre H. Huseby
  23.  *                    * Version 1.0, no modifications
  24.  *
  25.  **************************************************************************/
  26.  
  27.  
  28.  
  29.  
  30.  
  31. #include <stdlib.h>
  32. #include <stdio.h>
  33. #include <files.h>
  34.  
  35. #include "gifsave.h"
  36.  
  37.  
  38.  
  39.  
  40.  
  41. /**************************************************************************
  42.  *                                                                        *
  43.  *                       P R I V A T E    D A T A                         *
  44.  *                                                                        *
  45.  **************************************************************************/
  46.  
  47.  
  48. typedef unsigned Word;          /* At least two bytes (16 bits) */
  49. typedef unsigned char Byte;     /* Exactly one byte (8 bits) */
  50.  
  51.  
  52.  
  53. /*========================================================================*
  54.  =                                                                        =
  55.  =                             I/O Routines                               =
  56.  =                                                                        =
  57.  *========================================================================*/
  58.  
  59. short OutFile;           /* File to write to */
  60.  
  61.  
  62.  
  63. /*========================================================================*
  64.  =                                                                        =
  65.  =                      Routines to write a bit-file                      =
  66.  =                                                                        =
  67.  *========================================================================*/
  68.  
  69. static Byte Buffer[256];        /* There must be one to much !!! */
  70. static int  Index,              /* Current byte in buffer */
  71.             BitsLeft;           /* Bits left to fill in current byte. These
  72.                                 /* are right-justified */
  73.  
  74.  
  75.  
  76. /*========================================================================*
  77.  =                                                                        =
  78.  =                Routines to maintain an LZW-string table                =
  79.  =                                                                        =
  80.  *========================================================================*/
  81.  
  82. #define RES_CODES 2
  83.  
  84. #define HASH_FREE 0xFFFF
  85. #define NEXT_FIRST 0xFFFF
  86.  
  87. #define MAXBITS 12
  88. #define MAXSTR (1 << MAXBITS)
  89.  
  90. #define HASHSIZE 9973
  91. #define HASHSTEP 2039
  92.  
  93. #define HASH(index, lastbyte) (((lastbyte << 8) ^ index) % HASHSIZE)
  94.  
  95. static Byte *StrChr = NULL;
  96. static Word *StrNxt = NULL,
  97.             *StrHsh = NULL,
  98.             NumStrings;
  99.  
  100.  
  101.  
  102. /*========================================================================*
  103.  =                                                                        =
  104.  =                               Main routines                            =
  105.  =                                                                        =
  106.  *========================================================================*/
  107.  
  108. typedef struct {
  109.     Word LocalScreenWidth,
  110.          LocalScreenHeight;
  111.     Byte GlobalColorTableSize : 3,
  112.          SortFlag             : 1,
  113.          ColorResolution      : 3,
  114.          GlobalColorTableFlag : 1;
  115.     Byte BackgroundColorIndex;
  116.     Byte PixelAspectRatio;
  117. } ScreenDescriptor;
  118.  
  119. typedef struct {
  120.     Byte Separator;
  121.     Word LeftPosition,
  122.          TopPosition;
  123.     Word Width,
  124.          Height;
  125.     Byte LocalColorTableSize : 3,
  126.          Reserved            : 2,
  127.          SortFlag            : 1,
  128.          InterlaceFlag       : 1,
  129.          LocalColorTableFlag : 1;
  130. } ImageDescriptor;
  131.  
  132. static int  BitsPrPrimColor,    /* Bits pr primary color */
  133.             NumColors;          /* Number of colors in color table */
  134. static Byte *XXColorTable = NULL;
  135. static Word ScreenHeight,
  136.             ScreenWidth,
  137.             ImageHeight,
  138.             ImageWidth,
  139.             ImageLeft,
  140.             ImageTop,
  141.             RelPixX, RelPixY;         /* Used by InputByte() -function */
  142. static pascal short  (*XXGetPixel)(short x, short y);
  143.  
  144.  
  145.  
  146.  
  147.  
  148.  
  149.  
  150.  
  151.  
  152.  
  153. /**************************************************************************
  154.  *                                                                        *
  155.  *                   P R I V A T E    F U N C T I O N S                   *
  156.  *                                                                        *
  157.  **************************************************************************/
  158.  
  159.  
  160. /*========================================================================*
  161.  =                                                                        =
  162.  =                         Routines to do file IO                         =
  163.  =                                                                        =
  164.  *========================================================================*/
  165.  
  166. /*-------------------------------------------------------------------------
  167.  *
  168.  *  NAME:           Create()
  169.  *
  170.  *  DESCRIPTION:    Creates a new file, and enables referencing using the
  171.  *                  global variable OutFile. This variable is only used
  172.  *                  by these IO-functions, making it relatively simple to
  173.  *                  rewrite file IO.
  174.  *
  175.  *  PARAMETERS:     filename - Name of file to create
  176.  *
  177.  *  RETURNS:        GIF_OK       - OK
  178.  *                  GIF_ERRWRITE - Error opening the file
  179.  *
  180.  */
  181. static int XXCreate(FSSpec *filename)
  182. {
  183.     (void) FSpDelete(filename);
  184.     (void) FSpCreate(filename,'JVWR','GIFf',0);
  185.     if (FSpOpenDF(filename, fsRdWrPerm,&OutFile) != noErr) {
  186.         return GIF_ERRCREATE;
  187.     }
  188.     
  189.     return GIF_OK;
  190. }
  191.  
  192.  
  193.  
  194.  
  195.  
  196. /*-------------------------------------------------------------------------
  197.  *
  198.  *  NAME:           Write()
  199.  *
  200.  *  DESCRIPTION:    Output bytes to the current OutFile.
  201.  *
  202.  *  PARAMETERS:     buf - Pointer to buffer to write
  203.  *                  len - Number of bytes to write
  204.  *
  205.  *  RETURNS:        GIF_OK       - OK
  206.  *                  GIF_ERRWRITE - Error writing to the file
  207.  *
  208.  */
  209. static int Write(void *buf, long len)
  210. {
  211.     if (FSWrite(OutFile, &len, buf) != noErr) {
  212.         return GIF_ERRWRITE;
  213.     }
  214.     return GIF_OK;
  215. }
  216.  
  217.  
  218.  
  219.  
  220.  
  221. /*-------------------------------------------------------------------------
  222.  *
  223.  *  NAME:           WriteByte()
  224.  *
  225.  *  DESCRIPTION:    Output one byte to the current OutFile.
  226.  *
  227.  *  PARAMETERS:     b - Byte to write
  228.  *
  229.  *  RETURNS:        GIF_OK       - OK
  230.  *                  GIF_ERRWRITE - Error writing to the file
  231.  *
  232.  */
  233. static int WriteByte(Byte b)
  234. {
  235.     return Write(&b,1);
  236. }
  237.  
  238.  
  239.  
  240.  
  241.  
  242. /*-------------------------------------------------------------------------
  243.  *
  244.  *  NAME:           WriteWord()
  245.  *
  246.  *  DESCRIPTION:    Output one word (2 bytes with byte-swapping, like on
  247.  *                  the IBM PC) to the current OutFile.
  248.  *
  249.  *  PARAMETERS:     w - Word to write
  250.  *
  251.  *  RETURNS:        GIF_OK       - OK
  252.  *                  GIF_ERRWRITE - Error writing to the file
  253.  *
  254.  */
  255. static int WriteWord(Word w)
  256. {
  257.     int ret;
  258.     
  259.     ret = WriteByte(w & 0xFF);
  260.     if (ret == GIF_OK) {
  261.         ret = WriteByte(w >> 8);
  262.     }
  263.     return ret;
  264. }
  265.  
  266.  
  267.  
  268.  
  269.  
  270. /*-------------------------------------------------------------------------
  271.  *
  272.  *  NAME:           Close()
  273.  *
  274.  *  DESCRIPTION:    Close current OutFile.
  275.  *
  276.  *  PARAMETERS:     None
  277.  *
  278.  *  RETURNS:        Nothing
  279.  *
  280.  */
  281. static void Close(void)
  282. {
  283.     FSClose(OutFile);
  284. }
  285.  
  286.  
  287.  
  288.  
  289.  
  290. /*========================================================================*
  291.  =                                                                        =
  292.  =                      Routines to write a bit-file                      =
  293.  =                                                                        =
  294.  *========================================================================*/
  295.  
  296. /*-------------------------------------------------------------------------
  297.  *
  298.  *  NAME:           InitBitFile()
  299.  *
  300.  *  DESCRIPTION:    Initiate for using a bitfile. All output is sent to
  301.  *                  the current OutFile using the I/O-routines above.
  302.  *
  303.  *  PARAMETERS:     None
  304.  *
  305.  *  RETURNS:        Nothing
  306.  *
  307.  */
  308. static void InitBitFile(void)
  309. {
  310.     Buffer[Index = 0] = 0;
  311.     BitsLeft = 8;
  312. }
  313.  
  314.  
  315.  
  316.  
  317.  
  318. /*-------------------------------------------------------------------------
  319.  *
  320.  *  NAME:           ResetOutBitFile()
  321.  *
  322.  *  DESCRIPTION:    Tidy up after using a bitfile
  323.  *
  324.  *  PARAMETERS:     None
  325.  *
  326.  *  RETURNS:        0 - OK, -1 - error
  327.  *
  328.  */
  329. static int ResetOutBitFile(void)
  330. {
  331.     Byte numbytes;
  332.  
  333.  
  334.     /*
  335.      *  Find out how much is in the buffer
  336.      */
  337.     numbytes = Index + (BitsLeft == 8 ? 0 : 1);
  338.  
  339.     /*
  340.      *  Write whatever is in the buffer to the file
  341.      */
  342.     if (numbytes) {
  343.         if (WriteByte(numbytes) != GIF_OK)
  344.             return -1;
  345.  
  346.         if (Write(Buffer, numbytes) != GIF_OK)
  347.             return -1;
  348.  
  349.         Buffer[Index = 0] = 0;
  350.         BitsLeft = 8;
  351.     }
  352.  
  353.     return 0;
  354. }
  355.  
  356.  
  357.  
  358.  
  359.  
  360. /*-------------------------------------------------------------------------
  361.  *
  362.  *  NAME:           WriteBits()
  363.  *
  364.  *  DESCRIPTION:    Put the given number of bits to the outfile.
  365.  *
  366.  *  PARAMETERS:     bits    - bits to write from (right justified)
  367.  *                  numbits - number of bits to write
  368.  *
  369.  *  RETURNS:        bits written, or -1 on error.
  370.  *
  371.  */
  372. static int WriteBits(int bits, int numbits)
  373. {
  374.     int  bitswritten = 0;
  375.     Byte numbytes = 255;
  376.  
  377.  
  378.     do {
  379.         /*
  380.          *  If the buffer is full, write it.
  381.          */
  382.         if ((Index == 254 && !BitsLeft) || Index > 254) {
  383.             if (WriteByte(numbytes) != GIF_OK)
  384.                 return -1;
  385.  
  386.             if (Write(Buffer, numbytes) != GIF_OK)
  387.                 return -1;
  388.  
  389.             Buffer[Index = 0] = 0;
  390.             BitsLeft = 8;
  391.         }
  392.  
  393.         /*
  394.          *  Now take care of the two specialcases
  395.          */
  396.         if (numbits <= BitsLeft) {
  397.             Buffer[Index] |= (bits & ((1 << numbits) - 1)) << (8 - BitsLeft);
  398.             bitswritten += numbits;
  399.             BitsLeft -= numbits;
  400.             numbits = 0;
  401.         } else {
  402.             Buffer[Index] |= (bits & ((1 << BitsLeft) - 1)) << (8 - BitsLeft);
  403.             bitswritten += BitsLeft;
  404.             bits >>= BitsLeft;
  405.             numbits -= BitsLeft;
  406.  
  407.             Buffer[++Index] = 0;
  408.             BitsLeft = 8;
  409.         }
  410.     } while (numbits);
  411.  
  412.     return bitswritten;
  413. }
  414.  
  415.  
  416.  
  417.  
  418.  
  419. /*========================================================================*
  420.  =                                                                        =
  421.  =                Routines to maintain an LZW-string table                =
  422.  =                                                                        =
  423.  *========================================================================*/
  424.  
  425. /*-------------------------------------------------------------------------
  426.  *
  427.  *  NAME:           FreeStrtab()
  428.  *
  429.  *  DESCRIPTION:    Free arrays used in string table routines
  430.  *
  431.  *  PARAMETERS:     None
  432.  *
  433.  *  RETURNS:        Nothing
  434.  *
  435.  */
  436. static void FreeStrtab(void)
  437. {
  438.     if (StrHsh) {
  439.         DisposePtr((Ptr)StrHsh);
  440.         StrHsh = NULL;
  441.     }
  442.  
  443.     if (StrNxt) {
  444.         DisposePtr((Ptr)StrNxt);
  445.         StrNxt = NULL;
  446.     }
  447.  
  448.     if (StrChr) {
  449.         DisposePtr((Ptr)StrChr);
  450.         StrChr = NULL;
  451.     }
  452. }
  453.  
  454.  
  455.  
  456.  
  457.  
  458. /*-------------------------------------------------------------------------
  459.  *
  460.  *  NAME:           AllocStrtab()
  461.  *
  462.  *  DESCRIPTION:    Allocate arrays used in string table routines
  463.  *
  464.  *  PARAMETERS:     None
  465.  *
  466.  *  RETURNS:        GIF_OK     - OK
  467.  *                  GIF_OUTMEM - Out of memory
  468.  *
  469.  */
  470. static int AllocStrtab(void)
  471. {
  472.     /*
  473.      *  Just in case . . .
  474.      */
  475.     FreeStrtab();
  476.  
  477.     if ((StrChr = (Byte *) NewPtr(MAXSTR * sizeof(Byte))) == 0) {
  478.         FreeStrtab();
  479.         return GIF_OUTMEM;
  480.     }
  481.  
  482.     if ((StrNxt = (Word *) NewPtr(MAXSTR * sizeof(Word))) == 0) {
  483.         FreeStrtab();
  484.         return GIF_OUTMEM;
  485.     }
  486.  
  487.     if ((StrHsh = (Word *) NewPtr(HASHSIZE * sizeof(Word))) == 0) {
  488.         FreeStrtab();
  489.         return GIF_OUTMEM;
  490.     }
  491.  
  492.     return GIF_OK;
  493. }
  494.  
  495.  
  496.  
  497.  
  498.  
  499. /*-------------------------------------------------------------------------
  500.  *
  501.  *  NAME:           AddCharString()
  502.  *
  503.  *  DESCRIPTION:    Add a string consisting of the string of index plus
  504.  *                  the byte b.
  505.  *
  506.  *                  If a string of length 1 is wanted, the index should
  507.  *                  be 0xFFFF.
  508.  *
  509.  *  PARAMETERS:     index - Index to first part of string, or 0xFFFF is
  510.  *                          only 1 byte is wanted
  511.  *                  b     - Last byte in new string
  512.  *
  513.  *  RETURNS:        Index to new string, or 0xFFFF if no more room
  514.  *
  515.  */
  516. static Word AddCharString(Word index, Byte b)
  517. {
  518.     Word hshidx;
  519.  
  520.  
  521.     /*
  522.      *  Check if there is more room
  523.      */
  524.     if (NumStrings >= MAXSTR)
  525.         return 0xFFFF;
  526.  
  527.     /*
  528.      *  Search the string table until a free position is found
  529.      */
  530.     hshidx = HASH(index, b);
  531.     while (StrHsh[hshidx] != 0xFFFF)
  532.         hshidx = (hshidx + HASHSTEP) % HASHSIZE;
  533.  
  534.     /*
  535.      *  Insert new string
  536.      */
  537.     StrHsh[hshidx] = NumStrings;
  538.     StrChr[NumStrings] = b;
  539.     StrNxt[NumStrings] = (index != 0xFFFF) ? index : NEXT_FIRST;
  540.  
  541.     return NumStrings++;
  542. }
  543.  
  544.  
  545.  
  546.  
  547.  
  548. /*-------------------------------------------------------------------------
  549.  *
  550.  *  NAME:           FindCharString()
  551.  *
  552.  *  DESCRIPTION:    Find index of string consisting of the string of index
  553.  *                  plus the byte b.
  554.  *
  555.  *                  If a string of length 1 is wanted, the index should
  556.  *                  be 0xFFFF.
  557.  *
  558.  *  PARAMETERS:     index - Index to first part of string, or 0xFFFF is
  559.  *                          only 1 byte is wanted
  560.  *                  b     - Last byte in string
  561.  *
  562.  *  RETURNS:        Index to string, or 0xFFFF if not found
  563.  *
  564.  */
  565. static Word FindCharString(Word index, Byte b)
  566. {
  567.     Word hshidx, nxtidx;
  568.  
  569.  
  570.     /*
  571.      *  Check if index is 0xFFFF. In that case we need only
  572.      *  return b, since all one-character strings has their
  573.      *  bytevalue as their index
  574.      */
  575.     if (index == 0xFFFF)
  576.         return b;
  577.  
  578.     /*
  579.      *  Search the string table until the string is found, or
  580.      *  we find HASH_FREE. In that case the string does not
  581.      *  exist.
  582.      */
  583.     hshidx = HASH(index, b);
  584.     while ((nxtidx = StrHsh[hshidx]) != 0xFFFF) {
  585.         if (StrNxt[nxtidx] == index && StrChr[nxtidx] == b)
  586.             return nxtidx;
  587.         hshidx = (hshidx + HASHSTEP) % HASHSIZE;
  588.     }
  589.  
  590.     /*
  591.      *  No match is found
  592.      */
  593.     return 0xFFFF;
  594. }
  595.  
  596.  
  597.  
  598.  
  599.  
  600. /*-------------------------------------------------------------------------
  601.  *
  602.  *  NAME:           ClearStrtab()
  603.  *
  604.  *  DESCRIPTION:    Mark the entire table as free, enter the 2**codesize
  605.  *                  one-byte strings, and reserve the RES_CODES reserved
  606.  *                  codes.
  607.  *
  608.  *  PARAMETERS:     codesize - Number of bits to encode one pixel
  609.  *
  610.  *  RETURNS:        Nothing
  611.  *
  612.  */
  613. static void ClearStrtab(int codesize)
  614. {
  615.     int q, w;
  616.     Word *wp;
  617.  
  618.  
  619.     /*
  620.      *  No strings currently in the table
  621.      */
  622.     NumStrings = 0;
  623.  
  624.     /*
  625.      *  Mark entire hashtable as free
  626.      */
  627.     wp = StrHsh;
  628.     for (q = 0; q < HASHSIZE; q++)
  629.         *wp++ = HASH_FREE;
  630.  
  631.     /*
  632.      *  Insert 2**codesize one-character strings, and reserved codes
  633.      */
  634.     w = (1 << codesize) + RES_CODES;
  635.     for (q = 0; q < w; q++)
  636.         AddCharString(0xFFFF, q);
  637. }
  638.  
  639.  
  640.  
  641.  
  642.  
  643. /*========================================================================*
  644.  =                                                                        =
  645.  =                        LZW compression routine                         =
  646.  =                                                                        =
  647.  *========================================================================*/
  648.  
  649. /*-------------------------------------------------------------------------
  650.  *
  651.  *  NAME:           LZW_Compress()
  652.  *
  653.  *  DESCRIPTION:    Perform LZW compression as specified in the
  654.  *                  GIF-standard.
  655.  *
  656.  *  PARAMETERS:     codesize  - Number of bits needed to represent
  657.  *                              one pixelvalue.
  658.  *                  inputbyte - Function that fetches each byte to compress.
  659.  *                              Must return -1 when no more bytes.
  660.  *
  661.  *  RETURNS:        GIF_OK     - OK
  662.  *                  GIF_OUTMEM - Out of memory
  663.  *
  664.  */
  665. static int LZW_Compress(int codesize, int (*inputbyte)(void))
  666. {
  667.     register int c;
  668.     register Word index;
  669.     int  clearcode, endofinfo, numbits, limit, errcode;
  670.     Word prefix = 0xFFFF;
  671.  
  672.  
  673.     /*
  674.      *  Set up the given outfile
  675.      */
  676.     InitBitFile();
  677.  
  678.     /*
  679.      *  Set up variables and tables
  680.      */
  681.     clearcode = 1 << codesize;
  682.     endofinfo = clearcode + 1;
  683.  
  684.     numbits = codesize + 1;
  685.     limit = (1 << numbits) - 1;
  686.  
  687.     if ((errcode = AllocStrtab()) != GIF_OK)
  688.         return errcode;
  689.     ClearStrtab(codesize);
  690.  
  691.     /*
  692.      *  First send a code telling the unpacker to clear the stringtable.
  693.      */
  694.     WriteBits(clearcode, numbits);
  695.  
  696.     /*
  697.      *  Pack image
  698.      */
  699.     while ((c = inputbyte()) != -1) {
  700.         /*
  701.          *  Now perform the packing.
  702.          *  Check if the prefix + the new character is a string that
  703.          *  exists in the table
  704.          */
  705.         if ((index = FindCharString(prefix, c)) != 0xFFFF) {
  706.             /*
  707.              *  The string exists in the table.
  708.              *  Make this string the new prefix.
  709.              */
  710.             prefix = index;
  711.  
  712.         } else {
  713.             /*
  714.              *  The string does not exist in the table.
  715.              *  First write code of the old prefix to the file.
  716.              */
  717.             WriteBits(prefix, numbits);
  718.  
  719.             /*
  720.              *  Add the new string (the prefix + the new character)
  721.              *  to the stringtable.
  722.              */
  723.             if (AddCharString(prefix, c) > limit) {
  724.                 if (++numbits > 12) {
  725.                     WriteBits(clearcode, numbits - 1);
  726.                     ClearStrtab(codesize);
  727.                     numbits = codesize + 1;
  728.                 }
  729.                 limit = (1 << numbits) - 1;
  730.             }
  731.  
  732.             /*
  733.              *  Set prefix to a string containing only the character
  734.              *  read. Since all possible one-character strings exists
  735.              *  int the table, there's no need to check if it is found.
  736.              */
  737.             prefix = c;
  738.         }
  739.     }
  740.  
  741.     /*
  742.      *  End of info is reached. Write last prefix.
  743.      */
  744.     if (prefix != 0xFFFF)
  745.         WriteBits(prefix, numbits);
  746.  
  747.     /*
  748.      *  Write end of info -mark.
  749.      */
  750.     WriteBits(endofinfo, numbits);
  751.  
  752.     /*
  753.      *  Flush the buffer
  754.      */
  755.     ResetOutBitFile();
  756.  
  757.     /*
  758.      *  Tidy up
  759.      */
  760.     FreeStrtab();
  761.  
  762.     return GIF_OK;
  763. }
  764.  
  765.  
  766.  
  767.  
  768.  
  769. /*========================================================================*
  770.  =                                                                        =
  771.  =                              Other routines                            =
  772.  =                                                                        =
  773.  *========================================================================*/
  774.  
  775. /*-------------------------------------------------------------------------
  776.  *
  777.  *  NAME:           BitsNeeded()
  778.  *
  779.  *  DESCRIPTION:    Calculates number of bits needed to store numbers
  780.  *                  between 0 and n - 1
  781.  *
  782.  *  PARAMETERS:     n - Number of numbers to store (0 to n - 1)
  783.  *
  784.  *  RETURNS:        Number of bits needed
  785.  *
  786.  */
  787. static int BitsNeeded(Word n)
  788. {
  789.     int ret = 1;
  790.  
  791.  
  792.     if (!n--)
  793.         return 0;
  794.  
  795.     while (n >>= 1)
  796.         ++ret;
  797.  
  798.     return ret;
  799. }
  800.  
  801.  
  802.  
  803.  
  804.  
  805. /*-------------------------------------------------------------------------
  806.  *
  807.  *  NAME:           InputByte()
  808.  *
  809.  *  DESCRIPTION:    Get next pixel from image. Called by the
  810.  *                  LZW_Compress()-function
  811.  *
  812.  *  PARAMETERS:     None
  813.  *
  814.  *  RETURNS:        Next pixelvalue, or -1 if no more pixels
  815.  *
  816.  */
  817. static int InputByte(void)
  818. {
  819.     int ret;
  820.  
  821.  
  822.     if (RelPixY >= ImageHeight)
  823.         return -1;
  824.  
  825.     ret = XXGetPixel(ImageLeft + RelPixX, ImageTop + RelPixY);
  826.  
  827.     if (++RelPixX >= ImageWidth) {
  828.         RelPixX = 0;
  829.         ++RelPixY;
  830.     }
  831.  
  832.     return ret;
  833. }
  834.  
  835.  
  836.  
  837.  
  838.  
  839. /*-------------------------------------------------------------------------
  840.  *
  841.  *  NAME:           WriteScreenDescriptor()
  842.  *
  843.  *  DESCRIPTION:    Output a screen descriptor to the current GIF-file
  844.  *
  845.  *  PARAMETERS:     sd - Pointer to screen descriptor to output
  846.  *
  847.  *  RETURNS:        GIF_OK       - OK
  848.  *                  GIF_ERRWRITE - Error writing to the file
  849.  *
  850.  */
  851. static int WriteScreenDescriptor(ScreenDescriptor *sd)
  852. {
  853.     Byte tmp;
  854.  
  855.  
  856.     if (WriteWord(sd->LocalScreenWidth) != GIF_OK)
  857.         return GIF_ERRWRITE;
  858.     if (WriteWord(sd->LocalScreenHeight) != GIF_OK)
  859.         return GIF_ERRWRITE;
  860.     tmp = (sd->GlobalColorTableFlag << 7)
  861.           | (sd->ColorResolution << 4)
  862.           | (sd->SortFlag << 3)
  863.           | sd->GlobalColorTableSize;
  864.     if (WriteByte(tmp) != GIF_OK)
  865.         return GIF_ERRWRITE;
  866.     if (WriteByte(sd->BackgroundColorIndex) != GIF_OK)
  867.         return GIF_ERRWRITE;
  868.     if (WriteByte(sd->PixelAspectRatio) != GIF_OK)
  869.         return GIF_ERRWRITE;
  870.  
  871.     return GIF_OK;
  872. }
  873.  
  874.  
  875.  
  876.  
  877.  
  878. /*-------------------------------------------------------------------------
  879.  *
  880.  *  NAME:           WriteImageDescriptor()
  881.  *
  882.  *  DESCRIPTION:    Output an image descriptor to the current GIF-file
  883.  *
  884.  *  PARAMETERS:     id - Pointer to image descriptor to output
  885.  *
  886.  *  RETURNS:        GIF_OK       - OK
  887.  *                  GIF_ERRWRITE - Error writing to the file
  888.  *
  889.  */
  890. static int WriteImageDescriptor(ImageDescriptor *id)
  891. {
  892.     Byte tmp;
  893.  
  894.  
  895.     if (WriteByte(id->Separator) != GIF_OK)
  896.         return GIF_ERRWRITE;
  897.     if (WriteWord(id->LeftPosition) != GIF_OK)
  898.         return GIF_ERRWRITE;
  899.     if (WriteWord(id->TopPosition) != GIF_OK)
  900.         return GIF_ERRWRITE;
  901.     if (WriteWord(id->Width) != GIF_OK)
  902.         return GIF_ERRWRITE;
  903.     if (WriteWord(id->Height) != GIF_OK)
  904.         return GIF_ERRWRITE;
  905.     tmp = (id->LocalColorTableFlag << 7)
  906.           | (id->InterlaceFlag << 6)
  907.           | (id->SortFlag << 5)
  908.           | (id->Reserved << 3)
  909.           | id->LocalColorTableSize;
  910.     if (WriteByte(tmp) != GIF_OK)
  911.         return GIF_ERRWRITE;
  912.  
  913.     return GIF_OK;
  914. }
  915.  
  916.  
  917.  
  918.  
  919.  
  920.  
  921.  
  922.  
  923.  
  924.  
  925. /**************************************************************************
  926.  *                                                                        *
  927.  *                    P U B L I C    F U N C T I O N S                    *
  928.  *                                                                        *
  929.  **************************************************************************/
  930.  
  931.  
  932. /*-------------------------------------------------------------------------
  933.  *
  934.  *  NAME:           GIF_Create()
  935.  *
  936.  *  DESCRIPTION:    XXCreate a GIF-file, and write headers for both screen
  937.  *                  and image.
  938.  *
  939.  *  PARAMETERS:     filename  - Name of file to create (including extension)
  940.  *                  width     - Number of horisontal pixels on screen
  941.  *                  height    - Number of vertical pixels on screen
  942.  *                  numcolors - Number of colors in the colormaps
  943.  *                  colorres  - Color resolution. Number of bits for each
  944.  *                              primary color
  945.  *
  946.  *  RETURNS:        GIF_OK        - OK
  947.  *                  GIF_ERRCREATE - Couldn't create file
  948.  *                  GIF_ERRWRITE  - Error writing to the file
  949.  *                  GIF_OUTMEM    - Out of memory allocating color table
  950.  *
  951.  */
  952. pascal short GIF_Create(FSSpec *filename, short width, short height,
  953.                short numcolors, short colorres)
  954. {
  955.     int q, tabsize;
  956.     Byte *bp;
  957.     ScreenDescriptor SD;
  958.  
  959.  
  960.     /*
  961.      *  Initiate variables for new GIF-file
  962.      */
  963.     NumColors = numcolors ? (1 << BitsNeeded(numcolors)) : 0;
  964.     BitsPrPrimColor = colorres;
  965.     ScreenHeight = height;
  966.     ScreenWidth = width;
  967.  
  968.     /*
  969.      *  XXCreate file specified
  970.      */
  971.     if (XXCreate(filename) != GIF_OK)
  972.         return GIF_ERRCREATE;
  973.  
  974.     /*
  975.      *  Write GIF signature
  976.      */
  977.     if ((Write("GIF87a", 6)) != GIF_OK)
  978.         return GIF_ERRWRITE;
  979.  
  980.     /*
  981.      *  Initiate and write screen descriptor
  982.      */
  983.     SD.LocalScreenWidth = width;
  984.     SD.LocalScreenHeight = height;
  985.     if (NumColors) {
  986.         SD.GlobalColorTableSize = BitsNeeded(NumColors) - 1;
  987.         SD.GlobalColorTableFlag = 1;
  988.     } else {
  989.         SD.GlobalColorTableSize = 0;
  990.         SD.GlobalColorTableFlag = 0;
  991.     }
  992.     SD.SortFlag = 0;
  993.     SD.ColorResolution = colorres - 1;
  994.     SD.BackgroundColorIndex = 0;
  995.     SD.PixelAspectRatio = 0;
  996.     if (WriteScreenDescriptor(&SD) != GIF_OK)
  997.         return GIF_ERRWRITE;
  998.  
  999.     /*
  1000.      *  Allocate color table
  1001.      */
  1002.     if (XXColorTable) {
  1003.         DisposePtr((Ptr)XXColorTable);
  1004.         XXColorTable = NULL;
  1005.     }
  1006.     if (NumColors) {
  1007.         tabsize = NumColors * 3;
  1008.         if ((XXColorTable = (Byte *) NewPtr(tabsize * sizeof(Byte))) == NULL)
  1009.             return GIF_OUTMEM;
  1010.         else {
  1011.             bp = XXColorTable;
  1012.             for (q = 0; q < tabsize; q++)
  1013.                 *bp++ = 0;
  1014.         }
  1015.     }
  1016.  
  1017.     return 0;
  1018. }
  1019.  
  1020.  
  1021.  
  1022.  
  1023.  
  1024. /*-------------------------------------------------------------------------
  1025.  *
  1026.  *  NAME:           GIF_SetColor()
  1027.  *
  1028.  *  DESCRIPTION:    Set red, green and blue components of one of the
  1029.  *                  colors. The color components are all in the range
  1030.  *                  [0, (1 << BitsPrPrimColor) - 1]
  1031.  *
  1032.  *  PARAMETERS:     colornum - Color number to set. [0, NumColors - 1]
  1033.  *                  red      - Red component of color
  1034.  *                  green    - Green component of color
  1035.  *                  blue     - Blue component of color
  1036.  *
  1037.  *  RETURNS:        Nothing
  1038.  *
  1039.  */
  1040. pascal void GIF_SetColor(short colornum, short red, short green, short blue)
  1041. {
  1042.     long maxcolor;
  1043.     Byte *p;
  1044.  
  1045.  
  1046.     maxcolor = (1L << BitsPrPrimColor) - 1L;
  1047.     p = XXColorTable + colornum * 3;
  1048.     *p++ = (Byte) ((red * 255L) / maxcolor);
  1049.     *p++ = (Byte) ((green * 255L) / maxcolor);
  1050.     *p++ = (Byte) ((blue * 255L) / maxcolor);
  1051. }
  1052.  
  1053.  
  1054.  
  1055.  
  1056.  
  1057. /*-------------------------------------------------------------------------
  1058.  *
  1059.  *  NAME:           GIF_CompressImage()
  1060.  *
  1061.  *  DESCRIPTION:    Compress an image into the GIF-file previousely
  1062.  *                  created using GIF_Create(). All color values should
  1063.  *                  have been specified before this function is called.
  1064.  *
  1065.  *                  The pixels are retrieved using a user defined callback
  1066.  *                  function. This function should accept two parameters,
  1067.  *                  x and y, specifying which pixel to retrieve. The pixel
  1068.  *                  values sent to this function are as follows:
  1069.  *
  1070.  *                    x : [ImageLeft, ImageLeft + ImageWidth - 1]
  1071.  *                    y : [ImageTop, ImageTop + ImageHeight - 1]
  1072.  *
  1073.  *                  The function should return the pixel value for the
  1074.  *                  point given, in the interval [0, NumColors - 1]
  1075.  *
  1076.  *  PARAMETERS:     left     - Screen-relative leftmost pixel x-coordinate
  1077.  *                             of the image
  1078.  *                  top      - Screen-relative uppermost pixel y-coordinate
  1079.  *                             of the image
  1080.  *                  width    - Width of the image, or -1 if as wide as
  1081.  *                             the screen
  1082.  *                  height   - Height of the image, or -1 if as high as
  1083.  *                             the screen
  1084.  *                  getpixel - Address of user defined callback function.
  1085.  *                             (See above)
  1086.  *
  1087.  *  RETURNS:        GIF_OK       - OK
  1088.  *                  GIF_OUTMEM   - Out of memory
  1089.  *                  GIF_ERRWRITE - Error writing to the file
  1090.  *
  1091.  */
  1092. pascal short GIF_CompressImage(short left, short top, short width, short height,
  1093.                       pascal short (*getpixel)(short x, short y))
  1094. {
  1095.     int codesize, errcode;
  1096.     ImageDescriptor ID;
  1097.  
  1098.  
  1099.     if (width < 0) {
  1100.         width = ScreenWidth;
  1101.         left = 0;
  1102.     }
  1103.     if (height < 0) {
  1104.         height = ScreenHeight;
  1105.         top = 0;
  1106.     }
  1107.     if (left < 0)
  1108.         left = 0;
  1109.     if (top < 0)
  1110.         top = 0;
  1111.  
  1112.     /*
  1113.      *  Write global XXColorTable if any
  1114.      */
  1115.     if (NumColors)
  1116.         if ((Write(XXColorTable, NumColors * 3)) != GIF_OK)
  1117.             return GIF_ERRWRITE;
  1118.  
  1119.     /*
  1120.      *  Initiate and write image descriptor
  1121.      */
  1122.     ID.Separator = ',';
  1123.     ID.LeftPosition = ImageLeft = left;
  1124.     ID.TopPosition = ImageTop = top;
  1125.     ID.Width = ImageWidth = width;
  1126.     ID.Height = ImageHeight = height;
  1127.     ID.LocalColorTableSize = 0;
  1128.     ID.Reserved = 0;
  1129.     ID.SortFlag = 0;
  1130.     ID.InterlaceFlag = 0;
  1131.     ID.LocalColorTableFlag = 0;
  1132.  
  1133.     if (WriteImageDescriptor(&ID) != GIF_OK)
  1134.         return GIF_ERRWRITE;
  1135.  
  1136.     /*
  1137.      *  Write code size
  1138.      */
  1139.     codesize = BitsNeeded(NumColors);
  1140.     if (codesize == 1)
  1141.         ++codesize;
  1142.     if (WriteByte(codesize) != GIF_OK)
  1143.         return GIF_ERRWRITE;
  1144.  
  1145.     /*
  1146.      *  Perform compression
  1147.      */
  1148.     RelPixX = RelPixY = 0;
  1149.     XXGetPixel = getpixel;
  1150.     if ((errcode = LZW_Compress(codesize, InputByte)) != GIF_OK)
  1151.         return errcode;
  1152.  
  1153.     /*
  1154.      *  Write terminating 0-byte
  1155.      */
  1156.     if (WriteByte(0) != GIF_OK)
  1157.         return GIF_ERRWRITE;
  1158.  
  1159.     return GIF_OK;
  1160. }
  1161.  
  1162.  
  1163.  
  1164.  
  1165.  
  1166. /*-------------------------------------------------------------------------
  1167.  *
  1168.  *  NAME:           GIF_Close()
  1169.  *
  1170.  *  DESCRIPTION:    Close the GIF-file
  1171.  *
  1172.  *  PARAMETERS:     None
  1173.  *
  1174.  *  RETURNS:        GIF_OK       - OK
  1175.  *                  GIF_ERRWRITE - Error writing to file
  1176.  *
  1177.  */
  1178. pascal short GIF_Close(void)
  1179. {
  1180.     ImageDescriptor ID;
  1181.  
  1182.  
  1183.     /*
  1184.      *  Initiate and write ending image descriptor
  1185.      */
  1186.     ID.Separator = ';';
  1187.     if (WriteImageDescriptor(&ID) != GIF_OK)
  1188.         return GIF_ERRWRITE;
  1189.  
  1190.     /*
  1191.      *  Close file
  1192.      */
  1193.     Close();
  1194.  
  1195.     /*
  1196.      *  Release color table
  1197.      */
  1198.     if (XXColorTable) {
  1199.         DisposePtr((Ptr)XXColorTable);
  1200.         XXColorTable = NULL;
  1201.     }
  1202.  
  1203.     return GIF_OK;
  1204. }
  1205.